//////////////////////////////////////////////////////////////////////////////

//  Debug tool: debug_log

//////////////////////////////////////////////////////////////////////////////

#ifndef		__MAGUS_DEBUG_LOG_HPP
#define		__MAGUS_DEBUG_LOG_HPP

//////////////////////////////////////////////////////////////////////////////

//#ifndef NDEBUG

	#include <fstream>
	#include <string>
	#include <cassert>
	#include <ctime>
 	#include <cstdio>
 
	#include <magus/config.hpp>
	#include <magus/thread/mutex.hpp>

//#endif /* ! NDEBUG */

//////////////////////////////////////////////////////////////////////////////

namespace magus
{

//	#ifndef NDEBUG

		namespace magus_detail
		{
			const long MAX_LOGFILE_SIZE = 0x100000;   // 1M
			
			const char log_name[] = "./debug.log";
			const char bak_name[] = "./debug.bak";
			
			inline long log_size()
			{
				FILE* fp;
				if ((fp = fopen(log_name, "r" )) == NULL)
				{
					return -1;
				}
				fseek(fp, 0, SEEK_END);
				long len = ftell(fp);
				fclose(fp);
				return len;
			}
						
			// The file stream
			inline std::ofstream& log_file()
			{
				static int count = 0;
				static std::ofstream debug_log(log_name);
				
				count++;
				if (count%1000 == 0) {
					long size = log_size();
					if (size > MAX_LOGFILE_SIZE - 1024) {
						debug_log.close();
						debug_log.open(log_name);
					}
				}
				//assert(debug_log);
				return debug_log;
			}

			// The mutex
			inline magus::mutex& log_mtx()
			{
				static magus::mutex m;
				return m;
			}

			inline void decode_time(time_t t, short *yy, short *mm, short *dd, 
					short *hh, short *nn, short *ss)
			{
	#ifdef __MAGUS_SUN
				struct tm tms;
				localtime_r(&t, &tms);            
				*yy = tms.tm_year + 1900;
				*mm = tms.tm_mon + 1;
				*dd = tms.tm_mday;
				*hh = tms.tm_hour;
				*nn = tms.tm_min;
				*ss = tms.tm_sec;
	#else
				struct tm *tp;
				tp = localtime(&t);            
				*yy = tp->tm_year + 1900;
				*mm = tp->tm_mon + 1;
				*dd = tp->tm_mday;
				*hh = tp->tm_hour;
				*nn = tp->tm_min;
				*ss = tp->tm_sec;
	#endif		
			}
		}

		// In debug version, debug_output will wirte message to debug log file
		inline void debug_output(const std::string& msg, bool assertion = true)
		{
			if(!assertion)
				return;

   			short yy, mm, dd, h, m, s;
   			char tm_str[20];
			time_t now;
			time(&now);
   			magus_detail::decode_time(now, &yy, &mm, &dd, &h, &m, &s);
   			sprintf(tm_str, "%.2d-%.2d-%.2d %.2d:%.2d:%.2d", yy, mm, dd, h, m, s);

			magus::mutex::scoped_lock lock(magus_detail::log_mtx());
			std::string event_tm(tm_str);
			
			std::ofstream &ofs = magus_detail::log_file();
			if (ofs)
			    ofs << event_tm << " - " << msg << std::endl;
		}

		inline void debug_output(const char* msg, bool assertion = true)
		{
			if(!assertion)
				return;
			assert(msg != NULL);

   			short yy, mm, dd, h, m, s;
   			char tm_str[20];
			time_t now;
			time(&now);
   			magus_detail::decode_time(now, &yy, &mm, &dd, &h, &m, &s);
   			sprintf(tm_str, "%.2d-%.2d-%.2d %.2d:%.2d:%.2d", yy, mm, dd, h, m, s);

			magus::mutex::scoped_lock lock(magus_detail::log_mtx());
			std::string event_tm(tm_str);
			std::ofstream &ofs = magus_detail::log_file();
			if (ofs)
			    ofs << event_tm << " - " << msg << std::endl;
		}
/*
	#else		// #ifndef NDEBUG

		// In release version, they're nothing
		inline void debug_output(const std::string&, bool = true){};
		inline void debug_output(const char*, bool = true){};

	#endif		// #ifndef NDEBUG
*/

}	// namespace magus

//////////////////////////////////////////////////////////////////////////////

#endif		// #ifndef		__MAGUS_DEBUG_LOG_HPP
